#include "server.h"
#include "myview.h"

#include <QTcpServer>
#include <QTcpSocket>
#include <QDataStream>
#include <QNetworkInterface>


Server::Server(QObject *parent) :
	QObject(parent),
	tcpBlockSize(0)
{
	server = new QTcpServer(this);
	connect(server, SIGNAL(newConnection()), this, SLOT(serverConnected()));
	qDebug() << Q_FUNC_INFO << QNetworkInterface::allAddresses();
}

void Server::init(int port, QString rootIP, int rootPort)
{
	server->listen(QHostAddress::Any, port);
	qDebug() << Q_FUNC_INFO << server->serverAddress() << server->serverPort();


	root = new QTcpSocket(this);
	connections.append(root);
	connect(root, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
	connect(root, SIGNAL(readyRead()), this, SLOT(readyToRead()));

	QHostAddress ha;
	ha.setAddress(rootIP);
	root->connectToHost(ha, rootPort);

	qDebug() << Q_FUNC_INFO << root->peerAddress() << root->peerPort() << root->localPort();
}

int Server::listenPort()
{
	return server->serverPort();
}

void Server::readyToRead()
{
	QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
	if ( socket )
	{
		QDataStream s(socket);

		while (socket->bytesAvailable())
		{
			if ( tcpBlockSize == 0 )
			{
				if ( socket->bytesAvailable() < sizeof(quint16))
					return;

				s >> tcpBlockSize;
			}

			if ( socket->bytesAvailable() < tcpBlockSize )
				return;

			if ( tcpBlockSize == sizeof(int) )
			{
				int l;
				s >> l;
				emit lockState(l);

				sendLockMessage(static_cast<bool>(l), socket);
			}
			else
			{
				int mode, x, y;
				QPoint point;
				s >> mode;
				s >> x;
				s >> y;
				point.setX(x);
				point.setY(y);

				qDebug() << Q_FUNC_INFO << mode << point;

				emit paint(mode, point);

				sendPaintMessage(mode, point, socket);
			}

			tcpBlockSize = 0;
		}
	}
}

void Server::sendPaintMessage(int mode, QPoint point, QTcpSocket *excluded)
{
	foreach(QTcpSocket *s, connections)
	{
		if ( s != excluded )
		{
			sendPaint(s, mode, point);
		}
	}
}

void Server::onStartupScene(QTcpSocket *socket, QList<QPair<int, QPoint> > list)
{
	for(int i=0; i<list.size(); ++i)
	{
		sendPaint(socket, list.at(i).first, list.at(i).second);
	}
}

void Server::sendLockMessage(bool lock, QTcpSocket *excluded)
{
	foreach(QTcpSocket *socket, connections)
	{
		if ( socket != excluded )
		{
			sendLock(socket, lock);
		}
	}
}

void Server::sendPaint(QTcpSocket *socket, int mode, QPoint point)
{
	qDebug() << Q_FUNC_INFO << mode << point;

	QByteArray buf;
	QDataStream s(&buf, QIODevice::WriteOnly);
	s << (quint16)0;
	s << mode;
	s << point.x();
	s << point.y();
	s.device()->seek(0);
	s << (quint16)(buf.size() - sizeof(quint16));

	int i = socket->write(buf);

	qDebug() << Q_FUNC_INFO << i << socket->peerAddress() << socket->peerPort() << socket->localPort();

}

void Server::sendLock(QTcpSocket *socket, bool lock)
{
	QByteArray buf;
	QDataStream s(&buf, QIODevice::WriteOnly);
	s << (quint16)0;
	int l = lock ? MyView::OtherLock : MyView::NoLock;
	s << l;
	s.device()->seek(0);
	s << (quint16)(buf.size() - sizeof(quint16));

	socket->write(buf);
}

void Server::serverConnected()
{
	QTcpSocket *socket = server->nextPendingConnection();
	connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
	connect(socket, SIGNAL(readyRead()), this, SLOT(readyToRead()));
	connections.append(socket);
	qDebug() << Q_FUNC_INFO << socket->peerAddress() << socket->peerPort() << socket->localPort();

	emit appStateNeeded(socket);
}

void Server::socketDisconnected()
{
	QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
	qDebug() << Q_FUNC_INFO << socket->peerAddress() << socket->peerPort() << socket->localPort();
	if ( socket )
	{
		if ( socket == root )
		{
			root = 0;
		}
		connections.removeOne(socket);
	}
}
